package Byte

import (
	"errors"
	"strconv"
	"sync"
)

type Buffer struct {
	mutex sync.Mutex
	buff  []byte // 缓冲数组
	head  int    // 有效数据在缓冲数组中的head位置
	tail  int    // 有效数据在缓冲数组中的tail位置
	size  int    // 当前缓存数据的大小
	Max   int    // 可自动扩容的极限大小
	min   int    // 缓冲数组最小初始值
}

func NewBuffer() *Buffer {
	ptr := &Buffer{}
	ptr.reset()
	return ptr
}

func (e *Buffer) reset() {
	ptr := e

	ptr.head = 0
	ptr.tail = 0
	ptr.min = 1024
	ptr.size = ptr.min
	ptr.Max = 1024 * ptr.size
	ptr.buff = make([]byte, ptr.size)
}

func (e *Buffer) Reset() {
	e.mutex.Lock()
	defer e.mutex.Unlock()

	e.reset()
}

func (e *Buffer) cleanCavity() {
	// 场景1：如果空间很小，那么并不需要进行去除空洞的操作
	if e.size <= 16*e.min {
		return
	}

	cnt := e.tail - e.head

	// 场景2：空洞很大了，又是空的缓存，那么直接进行复位的操作
	if cnt == 0 {
		e.reset()
		return
	}

	// 场景3：空洞很大了，实际上还在缓存大小之内，那么移动数据
	if cnt < e.size/16 {
		// 移动数据
		copy(e.buff[:e.tail-e.head], e.buff[e.head:e.tail])
		e.tail -= e.head
		e.head = 0
		return
	}

	// 场景4：空洞很大了，并且缓存大小快达到MAX，缩小缓存
	if cnt < e.Max/16 {
		newCnt := cnt

		// 计算新的容量
		newSize := e.min
		for true {
			newSize *= 2
			if newSize >= newCnt {
				break
			}
		}

		// 搬迁数据
		buff := make([]byte, newSize)
		copy(buff, e.buff[e.head:e.tail])
		e.buff = buff
		e.size = newSize
		e.head = 0
		e.tail = cnt
		return
	}
}

func (e *Buffer) ReadableBytes() int {
	e.mutex.Lock()
	defer e.mutex.Unlock()

	cnt := e.tail - e.head
	return cnt
}

func (e *Buffer) WritableBytes() int {
	e.mutex.Lock()
	defer e.mutex.Unlock()

	cnt := e.tail - e.head
	return e.Max - cnt
}

func (e *Buffer) ReadByte() (byte, error) {
	e.mutex.Lock()
	defer e.mutex.Unlock()

	cnt := e.tail - e.head

	if cnt < 1 {
		return 0, errors.New("缓存为空")
	}

	data := e.buff[e.head]
	e.head += 1

	// 清理空洞
	e.cleanCavity()

	return data, nil
}

func (e *Buffer) TryRead(reader func(data []byte) (int, bool)) (int, bool) {
	e.mutex.Lock()
	defer e.mutex.Unlock()

	return reader(e.buff[e.head:e.tail])
}

func (e *Buffer) ReadBytes(count int) ([]byte, error) {
	e.mutex.Lock()
	defer e.mutex.Unlock()

	cnt := e.tail - e.head

	if cnt < count {
		return nil, errors.New("缓存为空")
	}

	data := e.buff[e.head : e.head+count]
	e.head += count

	// 清理空洞
	e.cleanCavity()

	return data, nil
}

func (e *Buffer) WriteBytes(data []byte) error {
	e.mutex.Lock()
	defer e.mutex.Unlock()

	cnt := e.tail - e.head

	wCnt := len(data)

	// 场景1：准备写入空数据
	if wCnt == 0 {
		return nil
	}

	// 场景2：当前缓存数组的尾部，还有可容纳的剩余空间
	if e.size-e.tail >= wCnt {
		// 追加数据
		copy(e.buff[e.tail:e.tail+wCnt], data)
		e.tail += wCnt
		return nil
	}

	// 场景3：当前缓存数组还有空间，但是尾部没有可容纳的剩余空间，需要挪动数组
	if e.size-cnt >= wCnt {
		// 移动数据
		copy(e.buff[:e.tail-e.head], e.buff[e.head:e.tail])
		e.tail -= e.head
		e.head = 0

		// 追加数据
		copy(e.buff[e.tail:e.tail+wCnt], data)
		e.tail += wCnt
		return nil
	}

	// 场景4：当前缓存数组没有空间，扩大数组
	if e.size-cnt < wCnt {
		//  扩容需要的大小判定
		newCnt := e.size + wCnt
		if e.Max < newCnt {
			return errors.New("缓存已达到最大可允许值" + strconv.Itoa(e.Max))
		}

		// 计算新的容量
		newSize := e.min
		for true {
			newSize *= 2
			if newSize >= newCnt {
				break
			}
		}

		// 搬迁数据
		buff := make([]byte, newSize)
		copy(buff, e.buff[e.head:e.tail])
		e.buff = buff
		e.size = newSize
		e.head = 0
		e.tail = cnt

		// 追加数据
		copy(e.buff[e.tail:e.tail+wCnt], data)
		e.tail += wCnt
		return nil
	}

	return errors.New("缓存出现异常")
}
